package org.mineground.commands.player;

import java.util.ArrayList;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandException;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jibble.pircbot.Colors;
import org.mineground.Main;
import org.mineground.PermissionNodes;
import org.mineground.Utilities;
import org.mineground.world.WarpLoader;

public class Warp implements CommandExecutor {
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) throws CommandException {
	Player player = (Player) sender;

	if (!player.hasPermission(PermissionNodes.PERMISSION_WARP_COMMAND)) {
            return true;
	}

	if (args.length == 0) {
	    player.sendMessage(ChatColor.RED + "* Usage: '/warp <Create/Delete/Private/Public/Password/Coords/Set/Point/List/Mylist/'Name/ID'>'");
	    return true;
	}

	if (args[0].equalsIgnoreCase("create")) {
	    if (args.length == 1) {
		player.sendMessage(ChatColor.RED + "* Usage: '/warp Create <Name> <Password (Additional)>'");
		return true;
	    }

	    if (Utilities.isNumeric(args[1])) {
		player.sendMessage(ChatColor.RED + "* Warp names may not consist out of numbers only.");
		return true;
	    }

	    if (!args[1].matches("^[0-9_a-zA-Z]*$") || args[1].length() > 20) {
		player.sendMessage(ChatColor.RED + "* Error: Only letters and _ allowed (Max. Length 20).");
		return true;
	    }

	    if (WarpLoader.isNameInUse(args[1])) {
		player.sendMessage(ChatColor.RED + "* Error: That name is already used by another warp.");
		return true;
	    }

	    if (player.getWorld().getBlockAt(player.getLocation()).getType() != Material.AIR) {
		player.sendMessage(ChatColor.RED + "* Error: This warp has an invalid spawn location.");
		return true;
	    }

	    String pw = "";
	    if (args.length == 3) {
		pw = args[2];
	    }

	    Location loc = player.getLocation();

	    if (!Main.getInstance().containsPlayer(player)) {
		player.sendMessage(ChatColor.RED + "Fatal Error: " + ChatColor.WHITE + "Your profile data hasn't been loaded, try to reconnect.");
		return true;
	    }

	    int id;
	    try {
		id = WarpLoader.add(Main.getInstance().getPlayer(player), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), loc.getYaw(), loc.getPitch(), player.getWorld().getName(), args[1], pw.hashCode(), true);
	    } catch (Exception e) {
		System.out.println("Exception while creating Warp: " + e);
		player.sendMessage(ChatColor.RED + "* Error: Couldn't create warp: " + e.getMessage());
		return true;
	    }

	    StringBuilder inform = new StringBuilder();
	    inform.append(ChatColor.GREEN);
	    inform.append("* Warp '");
	    inform.append(args[1]);
	    inform.append("' has been created. Use '/warp ");
	    inform.append(args[1]);
	    inform.append("' to get there.");

	    player.sendMessage(inform.toString());

	    inform = new StringBuilder();
	    inform.append(ChatColor.GREEN);
	    inform.append("* You may also use '/warp ");
	    inform.append(id);
	    inform.append("' for shorter usage.");

	    player.sendMessage(inform.toString());

	    player.sendMessage(ChatColor.WHITE + "* Use '/warp private' to protect your warp from other players.");

	    inform = new StringBuilder();
	    inform.append(Colors.BROWN);
	    inform.append("* ");
	    inform.append(Utilities.fixName(player));
	    inform.append(Colors.BROWN);
	    inform.append(" has created a new warp. (Name: ");
	    inform.append(args[1]);
	    inform.append(" / ID: ");
	    inform.append(id);
	    inform.append(" / Password: ");
	    inform.append((pw.length() > 0) ? (Colors.DARK_GREEN + "Yes") : (Colors.RED + "No"));
	    inform.append(Colors.BROWN);
	    inform.append(")");

	    Main.getInstance().getIRCHandler().sendMessage("@" + Main.getInstance().getConfigHandler().getIrcChannel(), inform.toString());
	}

	else if (args[0].equalsIgnoreCase("delete")) {
	    if (args.length == 1) {
		player.sendMessage(ChatColor.RED + "* Usage: '/warp Delete <Name/ID>'");
		return true;
	    }

	    int id = WarpLoader.getWarpID(args[1]);

	    if (id == WarpLoader.INVALID_WARP_ID || !WarpLoader.warps.containsKey(id)) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid warp name/ID.");
		return true;
	    }

	    org.mineground.world.Warp warp = WarpLoader.warps.get(id);
            
            int warpId = warp.getId();
            String warpName = warp.getName();
            
	    if (!WarpLoader.remove(warp, player)) {
		player.sendMessage(ChatColor.RED + "* Error: An unknown error occurred, please inform an admin about this.");
		return true;
	    }
            
            StringBuilder inform = new StringBuilder();
	    inform.append(ChatColor.GREEN);
	    inform.append("* Your warp '");
	    inform.append(warpName);
	    inform.append("' (Id: ");
	    inform.append(warpId);
	    inform.append(") has been removed from the database.");
	    player.sendMessage(inform.toString());

	    inform = new StringBuilder();
	    inform.append(Colors.BROWN);
	    inform.append("* ");
	    inform.append(Utilities.fixName(player));
	    inform.append(Colors.BROWN);
	    inform.append(" has removed warp '");
	    inform.append(warpName);
	    inform.append("' (Id: ");
	    inform.append(warpId);
	    inform.append(").");
	    Main.getInstance().getIRCHandler().sendMessage("@" + Main.getInstance().getConfigHandler().getIrcChannel(), inform.toString());
	}

	else if (args[0].equalsIgnoreCase("private") || args[0].equalsIgnoreCase("public")) {
	    if (args.length == 1) {
		player.sendMessage(ChatColor.RED + "* Usage: '/warp Private/Public <Name/ID>'");
		return true;
	    }

	    int id = WarpLoader.getWarpID(args[1]);

	    if (id == WarpLoader.INVALID_WARP_ID || !WarpLoader.warps.containsKey(id)) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid warp name/ID.");
		return true;
	    }

	    boolean toggle = args[0].equalsIgnoreCase("public");

	    org.mineground.world.Warp warp = WarpLoader.warps.get(id);
	    if (!WarpLoader.togglePrivate(warp, player, toggle)) {
		player.sendMessage(ChatColor.RED + "* Error: An unknown error occurred, please inform an admin about this.");
		return true;
	    }
	}

	else if (args[0].equalsIgnoreCase("password")) {
	    if (args.length < 3) {
		player.sendMessage(ChatColor.RED + "* Usage: '/warp Password <Name/ID> <Remove/'Password'>'");
		return true;
	    }

	    int id = WarpLoader.getWarpID(args[1]);

	    if (id == WarpLoader.INVALID_WARP_ID || !WarpLoader.warps.containsKey(id)) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid warp name/ID.");
		return true;
	    }

	    org.mineground.world.Warp warp = WarpLoader.warps.get(id);
	    if (!WarpLoader.setPassword(warp, player, args[2])) {
		player.sendMessage(ChatColor.RED + "* Error: An unknown error occurred, please inform an admin about this.");
		return true;
	    }
	}

	else if (args[0].equalsIgnoreCase("set")) {
	    if (args.length < 2) {
		player.sendMessage(ChatColor.RED + "* Usage: '/warp Set <Name/ID>'");
		return true;
	    }

	    if (player.getWorld().getBlockAt(player.getLocation()).getType() != Material.AIR) {
		player.sendMessage(ChatColor.RED + "* Error: This warp has an invalid spawn location.");
		return true;
	    }

	    int id = WarpLoader.getWarpID(args[1]);

	    if (id == WarpLoader.INVALID_WARP_ID || !WarpLoader.warps.containsKey(id)) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid warp name/ID.");
		return true;
	    }

	    org.mineground.world.Warp warp = WarpLoader.warps.get(id);

	    if (!WarpLoader.setPosition(warp, player)) {
		player.sendMessage(ChatColor.RED + "* Error: An unknown error occurred, please inform an admin about this.");
		return true;
	    }
	}

	else if (args[0].equalsIgnoreCase("point")) {
	    if (args.length < 2) {
		player.sendMessage(ChatColor.RED + "* Usage: '/warp Point <Name/ID>'");
		return true;
	    }

	    int id = WarpLoader.getWarpID(args[1]);

	    if (id == WarpLoader.INVALID_WARP_ID || !WarpLoader.warps.containsKey(id)) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid warp name/ID.");
		return true;
	    }

	    org.mineground.world.Warp warp = WarpLoader.warps.get(id);

	    if ((!warp.getPublic() || warp.hasPassword()) && !player.getName().equals(warp.getCreator())) {
		player.sendMessage(ChatColor.RED + "* Error: You do not have the permission to point your compass to that warp's position.");
		return true;
	    }

	    Location compassLoc = new Location(Main.getInstance().getServer().getWorld(warp.getWorld()), new Float(warp.getX()), new Float(warp.getY()), new Float(warp.getZ()));
	    player.setCompassTarget(compassLoc);

	    player.sendMessage(ChatColor.GREEN + "* Your compass now points to the warp's position.");
	}

	else if (args[0].equalsIgnoreCase("coords")) {
	    if (args.length < 2) {
		player.sendMessage(ChatColor.RED + "* Usage: '/warp Coords <Name/ID>'");
		return true;
	    }

	    int id = WarpLoader.getWarpID(args[1]);

	    if (id == WarpLoader.INVALID_WARP_ID || !WarpLoader.warps.containsKey(id)) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid warp name/ID.");
		return true;
	    }

	    org.mineground.world.Warp warp = WarpLoader.warps.get(id);

	    if ((!warp.getPublic() || warp.hasPassword()) && !player.getName().equals(warp.getCreator())) {
		player.sendMessage(ChatColor.RED + "* Error: You do not have the permission to get that warp's position.");
		return true;
	    }

	    StringBuilder out = new StringBuilder();
	    out.append(ChatColor.AQUA);
	    out.append("* Warp '");
	    out.append(warp.getName());
	    out.append("' is located at ");
	    out.append(warp.getX());
	    out.append(", ");
	    out.append(warp.getY());
	    out.append(", ");
	    out.append(warp.getZ());
	    out.append(" (");
	    out.append(warp.getWorld());
	    out.append(").");

	    player.sendMessage(out.toString());
	}

	else if (args[0].equalsIgnoreCase("list")) {
	    int page;

	    if (args.length > 1) {
		if (!Utilities.isNumeric(args[1])) {
		    player.sendMessage(ChatColor.RED + "* Error: Invalid page.");
		    player.sendMessage(ChatColor.RED + "* There are currently " + WarpLoader.getPages() + " pages.");
		    return true;
		}

		page = Integer.parseInt(args[1]);
	    }

	    else {
		page = 1;
	    }

	    if (page < 1 || page > WarpLoader.getPages() || WarpLoader.getPages() == 0) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid page.");
		player.sendMessage(ChatColor.RED + "* There are currently " + WarpLoader.getPages() + " pages.");
		return true;
	    }

	    ArrayList<org.mineground.world.Warp> list;
	    list = WarpLoader.showWarps(page);
	    StringBuilder listitem;

	    player.sendMessage(ChatColor.WHITE + "* Page " + page + " / " + WarpLoader.getPages());
	    player.sendMessage(ChatColor.WHITE + "==================");

	    for (org.mineground.world.Warp warp : list) {
		listitem = new StringBuilder();
		listitem.append(ChatColor.AQUA);
		listitem.append("* ");
		listitem.append(warp.getName());
		listitem.append("    (Creator: ");
		listitem.append(warp.getCreator());
		listitem.append(" / ID: ");
		listitem.append(warp.getId());
		listitem.append(")");
		player.sendMessage(listitem.toString());
	    }

	    player.sendMessage(ChatColor.WHITE + "==================");
	}

	else if (args[0].equalsIgnoreCase("mylist")) {
	    int page;

	    if (args.length > 1) {
		if (!Utilities.isNumeric(args[1])) {
		    player.sendMessage(ChatColor.RED + "* Error: Invalid page.");
		    player.sendMessage(ChatColor.RED + "* There are currently " + WarpLoader.getPages() + " pages.");
		    return true;
		}

		page = Integer.parseInt(args[1]);
	    }

	    else {
		page = 1;
	    }

	    if (page < 1 || page > WarpLoader.getPlayerPages(player) || WarpLoader.getPlayerPages(player) == 0) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid page.");
		player.sendMessage(ChatColor.RED + "* There are currently " + WarpLoader.getPlayerPages(player) + " pages of your warps.");
		return true;
	    }

	    ArrayList<org.mineground.world.Warp> list;
	    list = WarpLoader.getPlayerWarps(player, page);
	    StringBuilder listitem;

	    player.sendMessage(ChatColor.WHITE + "* Page " + page + " / " + WarpLoader.getPlayerPages(player));
	    player.sendMessage(ChatColor.WHITE + "==================");

	    for (org.mineground.world.Warp warp : list) {
		listitem = new StringBuilder();
		listitem.append(ChatColor.AQUA);
		listitem.append("* ");
		listitem.append(warp.getName());
		listitem.append("    (Creator: ");
		listitem.append(warp.getCreator());
		listitem.append(")");
		player.sendMessage(listitem.toString());
	    }

	    player.sendMessage(ChatColor.WHITE + "==================");
	}

	else {
	    int id = WarpLoader.getWarpID(args[0]);

	    if (id == WarpLoader.INVALID_WARP_ID || !WarpLoader.warps.containsKey(id)) {
		player.sendMessage(ChatColor.RED + "* Error: Invalid warp name/ID.");
		return true;
	    }

	    org.mineground.world.Warp warp = WarpLoader.warps.get(id);

	    if (warp.hasPassword()) {
		if (warp.getCreator().equals(player.getName()) || player.hasPermission("lvm.commands.warpoverride")) {
		    player.sendMessage(ChatColor.GREEN + "* Info: This warp is password protected.");
		    warp.teleport(player);
		    return true;
		}

		if (args.length == 1) {
		    player.sendMessage(ChatColor.RED + "* Error: This warp requires a password. Use '/warp <WarpID/Name> <Password>'.");
		    return true;
		}

		if (args[1].hashCode() != warp.getPassword()) {
		    player.sendMessage(ChatColor.RED + "* Error: Wrong password.");
		    return true;
		}

		else {
		    player.sendMessage(ChatColor.GREEN + "* Correct password!");
		    warp.teleport(player);
		    return true;
		}
	    }

	    if (!warp.getPublic()) {
		if (warp.getCreator().equals(player.getName()) || player.hasPermission("lvm.commands.warpoverride")) {
		    player.sendMessage(ChatColor.GREEN + "* Info: This warp is private.");
		    warp.teleport(player);
		    return true;
		}

		player.sendMessage(ChatColor.RED + "* Error: This warp is private and you do not have permissions to use it.");
		return true;
	    }

	    warp.teleport(player);
	}

	return true;
    }
}